//-----------------------------------------------------------------------
// <copyright file="CanonicalizeXml.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary>Converts a set of Xml files to the canonicalized form.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Xml
{
    using System;
    using System.Xml;
    using System.Globalization;
    using System.IO;
    using System.Collections;
    using System.Security.Cryptography.Xml;
    using System.Text;

    using Microsoft.Build.Framework;

    /// <summary>
    /// Converts a set of Xml files to the canonicalized form, in accordance with the algorithm 
    /// specified in http://www.w3.org/TR/xml-c14n
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[
    /// <Xml.CanonicalizeFile
    ///             SourceFiles="sourceFiles"
    ///             DestinationFiles="destinationFiles"
    ///             Timeout="timeout" >
    /// </Xml.CanonicalizeFile>
    /// ]]></code>
    /// <para>where:</para>
    /// <para><i>sourceFiles (Required)</i></para>
    /// <para>The full paths to the xml files that are to be transformed to their canonicalized form.</para>
    /// <para><i>destinationFiles</i></para>
    /// <para>The full paths to the canonicalized Xml files. These files will be created if they do not already exist.</para>
    /// </remarks>remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <Xml.CanonicalizeFile
    ///             SourceFiles="C:\SourceFiles\file1.xml;C:\TransformedFiles\file2.xml"
    ///             DestinationFiles="C:\TransformedFiles\file1.xml;C:\TransformedFiles\file2.xml"
    ///         </Xml.CanonicalizeFile> 
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class CanonicalizeFile : TaskBase
    {
        private string[] sourceFiles;
        private string[] destinationFiles;

        /// <summary>
        /// Initializes a new instance of the CanonicalizeFile class.
        /// </summary>
        public CanonicalizeFile()
        {
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            if (this.destinationFiles != null && this.destinationFiles.Length != this.sourceFiles.Length)
            {
                throw new TaskException("TwoVectorsMustHaveSameLength", this.destinationFiles.Length.ToString(CultureInfo.InvariantCulture), this.sourceFiles.Length.ToString(CultureInfo.InvariantCulture),
                    "DestinationFiles", "SourceFiles");
            }
            int i = 0;

            foreach (string source in sourceFiles)
            {
                string destination = this.destinationFiles[i++];
                if (source == destination)
                {
                    Log.LogError("CanonicalizeXml.DestinationSameAsSource", source);
                }
                else
                {
                    Log.LogMessageFromResources("CanonicalizeXml.Canonicalizing", source, destination);
                    byte[] fileContents = CanonicalizeXmlFromFile(source);
                    FileStream fs = System.IO.File.Create(destination);
                    fs.Write(fileContents, 0, fileContents.Length);
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// The full paths to the Xml files that are to be transformed to their canonicalized form.
        /// </summary>
        /// <value>The full paths to the xml files that are to be transformed to their canonicalized form.</value>
        [Required]
        public string[] SourceFiles
        {
            get
            {
                return (sourceFiles == null ? new string[0] : sourceFiles);
            }
            set
            {
                sourceFiles = value;
            }
        }

        /// <summary>
        /// The full paths to the canonicalized Xml files.
        /// </summary>
        /// <value>The full paths to the canonicalized Xml files. These files will be created if they do not already exist.</value>
        [Required]
        public string[] DestinationFiles
        {
            get
            {
                return (destinationFiles == null ? new string[0] : destinationFiles);
            }
            set
            {
                destinationFiles = value;
            }
        }

        /// <summary>
        /// Converts the Xml in the specified filename to its canonicalized form.
        /// </summary>
        /// <param name="filename">The full path to the Xml file</param>
        /// <returns>A byte array of the canonicalized xml</returns>
        private byte[] CanonicalizeXmlFromFile(string filename)
        {
            XmlDsigC14NTransform t = new XmlDsigC14NTransform(false);
            XmlDocument doc = new XmlDocument();

            doc.Load(filename);

            t.LoadInput(doc);
            byte[] ret;

            using (Stream s = (Stream) t.GetOutput(typeof(Stream)))
            {
                s.Position = 0;
                ret = new byte[s.Length];
                if (s.Read(ret, 0, (int) s.Length) != s.Length)
                {
                    throw new TaskException("General.ErrorReadingStream");
                }
            }

            return ret;
        }
    }
}

